home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 076-100 / disk_086 / cmd / cmd.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  15KB  |  557 lines

  1. /* Cmd.c --- v3 --- Carolyn Scheppner  CBM  05/87
  2.  *
  3.  * Copyright (c) 1987  Commodore Business Machines - All Rights Reserved
  4.  *    This code may be freely non-commercially redistributed.
  5.  *
  6.  * Redirects exec serial or parallel device CMD_WRITEs to a file
  7.  *  (for the purpose of capturing printer output in a file)
  8.  * Built upon fragments of Read (author?) and NoFastMem (Andy Finkel)
  9.  *
  10.  * CLI Usage:  [run] cmd [-s] [-m] [-n] devicename filename
  11.  *   -s (Skip) skips any short initial write (usually a Reset if screendump)
  12.  *   -m (Multiple) causes cmd to remain installed for multiple files
  13.  *   -n (Notify) enables helpful progress messages 
  14.  *   devicename serial or parallel
  15.  *
  16.  * WB Usage:  Just doubleclick.
  17.  *            Specify the args in your icon's ToolTypes (use WB Info)
  18.  *            Built-in defaults are:
  19.  *               DEVICE=parallel
  20.  *               FILE=ram:CMD_file
  21.  *               SKIP=FALSE
  22.  *               MULTIPLE=FALSE
  23.  *               NOTIFY=FALSE
  24.  *
  25.  *   Note: On a screen dump, first CMD_WRITE is usually a printer RESET.
  26.  *         The printer device then delays long enough for the reset
  27.  *         to complete, to prevent the loss of subsequent output data.
  28.  *         When the dump is instead captured in a file, this delay
  29.  *         is of course lost.  If your printer driver outputs a reset
  30.  *         at the start of a dump (as ours do), use the -s (SKIP) option
  31.  *         to keep the initial CMD_WRITE out of the file.
  32.  *
  33.  * Sorry about the busywait synchronization of the device wedge
  34.  * and the main process.  The purpose was to avoid unnecessary
  35.  * meddling with the message structures and the device's signals.
  36.  *
  37.  * v2 mods: changes to MyBeginIO for -1 and 0 length CMD_WRITES, usage
  38.  * v3 mods: added buffering of small writes to speed file IO
  39.  *
  40.  * Linkage info (requires assembler module cmda):
  41.  *    FROM    LIB:Astartup.obj, cmd.o, cmda.o
  42.  *    TO      cmd
  43.  *    LIBRARY LIB:Amiga.lib,LIB:LC.lib
  44.  */
  45.  
  46. #include "exec/types.h" 
  47. #include "exec/memory.h" 
  48. #include "exec/io.h"
  49. #include "exec/libraries.h"
  50. #include "libraries/dos.h" 
  51. #include "libraries/dosextens.h"
  52. #include "workbench/startup.h"
  53. #include "workbench/workbench.h"
  54. #include "devices/serial.h" 
  55. #include "devices/parallel.h" 
  56.  
  57. #define TOUPPER(c)      ((c)>='a'&&(c)<='z'?(c)-'a'+'A':(c)) 
  58. #define HIGHER(x,y)     ((x)>(y)?(x):(y))
  59. #define WBUFLEN   2048L
  60. #define INBUFLEN    40L
  61. #define REQSIZE    120L    /* should be big enough or any OpenDevice */
  62.  
  63. #define DEV_CLOSE    LIB_CLOSE
  64. #define DEV_EXPUNGE  LIB_EXPUNGE
  65. /*      DEV_BEGINIO  (-30)       defined in exec/io.h */
  66.  
  67. #define OPEN_SIG   SIGBREAKF_CTRL_E
  68. #define WRITE_SIG  SIGBREAKF_CTRL_F
  69. #define CLOSE_SIG  SIGBREAKF_CTRL_D
  70. #define BREAK_SIG  SIGBREAKF_CTRL_C
  71.  
  72. #define SHORT_WRITE (8L)
  73.  
  74. extern VOID  myBeginIO();  /* The assembler entry */
  75. extern VOID  myClose();    /* The assembler entry */
  76. extern VOID  myExpunge();  /* The assembler routine */
  77.  
  78. extern struct MsgPort *CreatePort(); 
  79. extern struct WBStartup *WBenchMsg;
  80.  
  81. ULONG  RealBeginIO, NewBeginIO;
  82. ULONG  RealClose,   NewClose;
  83. ULONG  RealExpunge, NewExpunge;
  84.  
  85. char *noMem      = "Out of memory\n";
  86. char *portName   = "cas_TMP_CMD_PORT";
  87. char *conSpec    = "CON:20/20/600/40/ CMD v3";
  88.  
  89. char u1[]={"\nCLI Usage: [run] Cmd [-s] [-m] [-n] devicename filename\n"};
  90. char u2[]={"  devicename = serial or parallel\n"};
  91. char u3[]={"  -s = SKIP any short initial write (usually a reset if screendump)\n"};
  92. char u4[]={"  -m = installed for MULTIPLE files until Break or CTRL_C\n"};
  93. char u5[]={"  -n = enables NOTIFY (helpful progress messages)\n\n"};
  94. char u6[]={"WB Tooltypes: DEVICE, FILE, and booleans SKIP,MULTIPLE,NOTIFY\n"};
  95. char u7[]={"   Cancel installation for multiple files by reclicking\n\n"};
  96. char *us[7] = {u1,u2,u3,u4,u5,u6,u7};
  97. char *morehelp = "Type  cmd ?  for more help\n\n";
  98.  
  99. char *prevTaskName = NULL;
  100. char *outFileName, *deviceName;
  101. char mainTaskName[40];
  102. char wbDev[INBUFLEN], wbFile[INBUFLEN];
  103. char sbuf[120], *wbuf = 0;
  104.  
  105. struct Device *TheDevice;
  106. struct Task   *otherTask, *mainTask;
  107.  
  108. struct IOStdReq *myReq, *ioR;
  109. struct MsgPort  *port; 
  110.  
  111.  
  112. LONG  wLen = 1, outFile = NULL;
  113. ULONG total = 0;
  114. ULONG IconBase = NULL;
  115. BOOL  Error1 = TRUE, Skip = FALSE, Multiple = FALSE, Notify = FALSE;
  116. BOOL  Done = FALSE, FromWb = FALSE, MainBusy = FALSE;
  117. int   reqcnt = 0, writecnt = 0, filecnt = 0; fnLen, wi;
  118.  
  119.  
  120. VOID MyBeginIO(ior)
  121. struct IOStdReq *ior;
  122.    {
  123.    reqcnt += 1;
  124.    if(ior->io_Command == CMD_WRITE)
  125.       {
  126.       if(!writecnt)
  127.          {
  128.          while(MainBusy);
  129.          MainBusy = TRUE;
  130.          Signal(mainTask,OPEN_SIG);
  131.          while(MainBusy);
  132.          }
  133.  
  134.       /* If device CMD_WRITE uses length -1, convert to actual length */
  135.       if(ior->io_Length==-1)  ior->io_Length = strlen(ior->io_Data);
  136.  
  137.       if((!Skip)||(writecnt>0)||(ior->io_Length > SHORT_WRITE))
  138.          {
  139.          if(ior->io_Length)
  140.             {
  141.             while(MainBusy);
  142.             MainBusy = TRUE;
  143.             ioR = ior;
  144.             Signal(mainTask,WRITE_SIG);  /* Signal write */
  145.             while(MainBusy);
  146.             }
  147.          }
  148.       writecnt += 1;
  149.       ior->io_Actual = ior->io_Length;
  150.       }
  151.    if(!(ior->io_Flags & IOF_QUICK))  ReplyMsg(ior);
  152.    }
  153.  
  154. VOID MyClose(ior)
  155. struct IOStdReq *ior;
  156.    {
  157.    /* Note - Exec has us in a forbid here */
  158.    if(reqcnt) /* Ignores DOS's initial Open/Close/Open */
  159.       {
  160.       Signal(mainTask,CLOSE_SIG);  /* Signal Close */
  161.       }
  162.    }
  163.  
  164. main(argc, argv) 
  165. UWORD argc; 
  166. TEXT *argv[]; 
  167.    { 
  168.    ULONG signals;
  169.    int k;
  170.  
  171.    FromWb = (argc==0) ? TRUE : FALSE;
  172.  
  173.    if(FromWb)
  174.       {
  175.       getWbArgs(WBenchMsg);
  176.       deviceName  = wbDev;
  177.       outFileName = wbFile;
  178.       }
  179.    else
  180.       {
  181.       if(strEqu(argv[1], "?"))  usageHelpExit();
  182.       if(argc<3) usageExit();
  183.  
  184.       for(k=1; argv[k][0]=='-'; k++)
  185.          {
  186.          if(argv[k][1] == 's')  Skip = TRUE;
  187.          if(argv[k][1] == 'm')  Multiple = TRUE;
  188.          if(argv[k][1] == 'n')  Notify = TRUE;
  189.          }
  190.       if(argc-k < 2)  usageExit();
  191.       deviceName  = argv[k++];
  192.       outFileName = argv[k];
  193.       }
  194.  
  195.    fnLen = strlen(outFileName); /* Used if Multiple extension added */
  196.  
  197.    /* Result will be mainTaskName = "cas_CMD_whatever.device"
  198.     *   with deviceName pointing to the eighth character
  199.     */
  200.    strcpy(&mainTaskName[0],"cas_CMD_");
  201.    strcpy(&mainTaskName[strlen(mainTaskName)],deviceName);
  202.    strcpy(&mainTaskName[strlen(mainTaskName)],".device");
  203.    deviceName = &mainTaskName[8];
  204.  
  205.    Forbid();
  206.    if(otherTask = (struct Task *)FindTask(mainTaskName))
  207.       {
  208.       Permit();
  209.       if(FromWb) Signal(otherTask,BREAK_SIG);
  210.       else printf("Device already redirected... exiting\n");
  211.       cleanexit();
  212.       }
  213.  
  214.    mainTask = (struct Task *)FindTask(NULL);
  215.    prevTaskName = mainTask->tc_Node.ln_Name;
  216.    mainTask->tc_Node.ln_Name = mainTaskName;
  217.    Permit();
  218.      
  219.    /* initialize */
  220.    if(!(wbuf = (char *)AllocMem(WBUFLEN, MEMF_PUBLIC|MEMF_CLEAR)))
  221.       cleanexit("Can't allocate write buffer\n");
  222.  
  223.    if(!(port = CreatePort(portName, 0)))  cleanexit("Can't open port\n");
  224.  
  225.    myReq = (struct IOStdReq *)AllocMem(REQSIZE,MEMF_CLEAR|MEMF_PUBLIC);
  226.    if (!myReq)  cleanexit(noMem);
  227.  
  228.    myReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  229.    myReq->io_Message.mn_ReplyPort = port;
  230.  
  231.    if(OpenDevice(deviceName, 0, myReq, 0))
  232.       {
  233.       sprintf(sbuf,"Can't open %s\n",deviceName);
  234.       cleanexit(sbuf);
  235.       }
  236.    TheDevice = myReq->io_Device;
  237.  
  238.    /* Install device IO redirection */
  239.  
  240.    Forbid();
  241.    RealBeginIO = SetFunction(TheDevice, DEV_BEGINIO, myBeginIO);
  242.    RealClose   = SetFunction(TheDevice, DEV_CLOSE,   myClose);
  243.    RealExpunge = SetFunction(TheDevice, DEV_EXPUNGE, myExpunge);
  244.    Permit();
  245.  
  246.    /* Expunge disabled, CloseDevice so another can open it */
  247.    CloseDevice(myReq);
  248.  
  249.    if(Notify)
  250.       {
  251.       sprintf(sbuf,"Cmd redirection of %s installed\n",deviceName);
  252.       message(sbuf);
  253.       }
  254.  
  255.    while(!Done)
  256.       {
  257.       signals = Wait(OPEN_SIG|WRITE_SIG|CLOSE_SIG|BREAK_SIG);
  258.  
  259.       if(signals & OPEN_SIG)   /* Open */
  260.          {
  261.          if(!outFile)   /* No output file currently open */
  262.             {
  263.             if(Multiple)  /* If Multiple, add .n extension to filename */
  264.                {
  265.                filecnt++;
  266.                sprintf(&outFileName[fnLen],".%ld",filecnt);
  267.                }
  268.              /* open output file */
  269.             outFile = Open(outFileName, MODE_NEWFILE);
  270.             wLen = 1;
  271.             total = 0;
  272.             wi = 0;        /* Index into write buffer */
  273.             Error1 = TRUE;
  274.  
  275.             if(Notify)
  276.                {
  277.                sprintf(sbuf,"Redirecting %s to %s\n",
  278.                          deviceName,outFileName);
  279.                message(sbuf);
  280.                }
  281.  
  282.             }
  283.          }
  284.  
  285.       if(signals & WRITE_SIG)   /* Write */
  286.          {
  287.          if((outFile)&&(wLen > -1))
  288.             {
  289.             wLen = bufOrWrite(outFile,ioR->io_Data,ioR->io_Length);
  290.             }
  291.          else if(Error1)
  292.             {
  293.             message("Cmd file error: Cancel device output\n");
  294.             Error1 = FALSE;
  295.             }
  296.          }
  297.  
  298.       if(signals & (CLOSE_SIG|BREAK_SIG))
  299.          {
  300.          /* Close file now so user can copy even if something is wrong */
  301.          /* Null the handle - to prevent Write or re-Close */
  302.          if(!Multiple)  signals |= BREAK_SIG;
  303.          if(outFile)
  304.             {
  305.             /* Write buffer contents */
  306.             if((wi>0)&&(wLen>-1)) wLen = myWrite(outFile,wbuf,wi);
  307.  
  308.             Forbid();
  309.             Close(outFile);
  310.             outFile = NULL;
  311.             writecnt = 0;
  312.             reqcnt = 0;
  313.             Permit();
  314.  
  315.             if((!Multiple)||(Notify))
  316.                {
  317.                sprintf(sbuf,"Redirected %ld bytes from %s to %s\n",
  318.                           total,deviceName,outFileName);
  319.                message(sbuf);
  320.                }
  321.             }
  322.          }
  323.  
  324.       if(signals & BREAK_SIG)
  325.          {
  326.          while(!Done)
  327.             {
  328.             /* Wait till we can reopen the device */
  329.             while(OpenDevice(deviceName, 0L, myReq, 0L))  Delay(50L);
  330.  
  331.             /* If it's been re-loaded, we can leave            */
  332.             /* Shouldn't be possible since we disabled Expunge */
  333.             if((ULONG)myReq->io_Device != (ULONG)TheDevice)
  334.                {
  335.                Done = TRUE;
  336.                }
  337.             else
  338.                {
  339.                Forbid();
  340.  
  341.                NewBeginIO = SetFunction(TheDevice, DEV_BEGINIO, RealBeginIO);
  342.                NewClose   = SetFunction(TheDevice, DEV_CLOSE,   RealClose);
  343.                NewExpunge = SetFunction(TheDevice, DEV_EXPUNGE, RealExpunge);
  344.  
  345.                if((NewBeginIO != (ULONG)myBeginIO)
  346.                    ||(NewClose != (ULONG)myClose)
  347.                      ||(NewExpunge != (ULONG)myExpunge))
  348.                   {
  349.                   /* Someone else has changed the vectors */
  350.                   /* We put theirs back - can't exit yet  */
  351.                   SetFunction(TheDevice, DEV_BEGINIO, NewBeginIO);                  SetFunction(TheDevice, DEV_CLOSE  , NewClose);
  352.                   SetFunction(TheDevice, DEV_CLOSE,   NewClose);                  SetFunction(TheDevice, DEV_CLOSE  , NewClose);
  353.                   SetFunction(TheDevice, DEV_EXPUNGE, NewExpunge);
  354.                   }
  355.                else
  356.                   {
  357.                   Done = TRUE;
  358.                   }
  359.                Permit();
  360.                }
  361.             CloseDevice(myReq);
  362.             if(!Done)  message("Vectors have changed - can't restore\n");
  363.             }
  364.          }
  365.       MainBusy = FALSE;
  366.       }
  367.  
  368.    sprintf(sbuf,"\nCmd redirection of %s removed\n", deviceName);
  369.    cleanexit(sbuf);
  370.    }
  371.  
  372.  
  373. /* Output buffering */
  374.  
  375. bufOrWrite(fh,data,len)
  376. LONG fh;
  377. char *data;
  378. int len;
  379.    {
  380.    int k, wlen;
  381.  
  382.    wlen = len;
  383.  
  384.    /* If possible, just buffer the output data */
  385.    if(len <  WBUFLEN - wi)
  386.       {
  387.       for(k=0; k<len; k++, wi++)  wbuf[wi] = data[k];
  388.       }
  389.    else
  390.       {
  391.       /* Else output any buffered data to the file */
  392.       if(wi>0)  wlen = myWrite(fh,wbuf,wi);
  393.       wi = 0;
  394.  
  395.       /* Then either buffer or write out current request */
  396.       if(wlen > -1)
  397.          {
  398.          if(len < WBUFLEN)
  399.             {
  400.             for(k=0; k<len; k++, wi++)  wbuf[wi] = data[k];
  401.             wlen = len;
  402.             }
  403.          else
  404.             {
  405.             wlen = myWrite(fh,data,len);
  406.             }
  407.          }
  408.       }
  409.    return(wlen);
  410.    }
  411.  
  412.  
  413. /* myWrite also updates total */
  414. myWrite(fh,data,len)
  415. LONG fh;
  416. char *data;
  417. int len;
  418.    {
  419.    int wlen;
  420.  
  421.    wlen = Write(fh,data,len);
  422.    if (wlen > -1) total += wlen;
  423.    return(wlen);
  424.    }
  425.  
  426.  
  427. /* Cleanup and exits */
  428.  
  429. usageHelpExit()
  430.    { 
  431.    int k;
  432.    for(k=0; k<7; k++) printf(us[k]);
  433.    exit(RETURN_OK);
  434.    } 
  435.  
  436. usageExit()
  437.    { 
  438.    printf(u1);
  439.    printf(morehelp);
  440.    exit(RETURN_OK);
  441.    } 
  442.  
  443. cleanexit(s)
  444.    char  *s;
  445.    {
  446.    message(s);
  447.    cleanup();
  448.    exit(RETURN_OK);
  449.    }
  450.  
  451. cleanup()
  452.    {
  453.    if(myReq)   FreeMem(myReq,REQSIZE);
  454.    if(port)    DeletePort(port);
  455.    if(outFile) Close(outFile);
  456.    if(wbuf)    FreeMem(wbuf,WBUFLEN);
  457.  
  458.    Forbid();
  459.    if(prevTaskName) mainTask->tc_Node.ln_Name = prevTaskName;
  460.    Permit();
  461.    }
  462.  
  463.  
  464. message(s)
  465. char *s;
  466.    {
  467.    LONG con;
  468.  
  469.    if((!FromWb)&&(*s)) printf(s);
  470.    if((FromWb)&&(*s)&&(con = Open(conSpec,MODE_OLDFILE)))
  471.       {
  472.       Write(con,s,strlen(s));
  473.       Delay(120L);
  474.       Close(con);
  475.       }
  476.    }
  477.  
  478.  
  479. getWbArgs(wbMsg)
  480. struct WBStartup *wbMsg;
  481.    {
  482.    struct WBArg  *wbArg;
  483.    struct DiskObject *diskobj;
  484.    char **toolarray;
  485.    char *s;
  486.  
  487.    /* Defaults */
  488.    strcpy(wbDev,"parallel");
  489.    strcpy(wbFile,"ram:CMD_file");
  490.    Skip = FALSE;
  491.    Multiple = FALSE;
  492.    Notify = FALSE;
  493.  
  494.    wbArg = wbMsg->sm_ArgList;
  495.  
  496.    if((IconBase = OpenLibrary("icon.library", 0)))
  497.       {
  498.       diskobj=(struct DiskObject *)GetDiskObject(wbArg->wa_Name);
  499.       if(diskobj)
  500.          {
  501.          toolarray = (char **)diskobj->do_ToolTypes;
  502.  
  503.          if(s=(char *)FindToolType(toolarray,"DEVICE"))  strcpy(wbDev,s);
  504.          if(s=(char *)FindToolType(toolarray,"FILE"))    strcpy(wbFile,s);
  505.          if(s=(char *)FindToolType(toolarray,"SKIP"))
  506.             {
  507.             if(strEqu(s,"TRUE"))  Skip = TRUE;
  508.             }
  509.          if(s=(char *)FindToolType(toolarray,"MULTIPLE"))
  510.             {
  511.             if(strEqu(s,"TRUE"))  Multiple = TRUE;
  512.             }
  513.          if(s=(char *)FindToolType(toolarray,"NOTIFY"))
  514.             {
  515.             if(strEqu(s,"TRUE"))  Notify = TRUE;
  516.             }
  517.          FreeDiskObject(diskobj);
  518.          }
  519.       CloseLibrary(IconBase);
  520.       }
  521.    }
  522.  
  523.  
  524. /* String functions */
  525.  
  526. strEqu(p, q) 
  527. TEXT *p, *q; 
  528.    { 
  529.    while(TOUPPER(*p) == TOUPPER(*q))
  530.       {
  531.       if (*(p++) == 0)  return(TRUE);
  532.       ++q; 
  533.       }
  534.    return(FALSE);
  535.    } 
  536.  
  537. strlen(s)
  538. char *s;
  539.    {
  540.    int i = 0;
  541.    while(*s++) i++;
  542.    return(i);
  543.    }
  544.  
  545. strcpy(to,from)
  546. char *to, *from;
  547.    {
  548.    do
  549.       {
  550.       *to++ = *from;
  551.       }
  552.    while(*from++);
  553.    }
  554.  
  555. /* end */
  556.  
  557.